<?xml version="1.0" encoding="ISO-8859-1"?>
<!DOCTYPE html PUBLIC "-//W3C//DTD XHTML 1.0 Strict//EN" "http://www.w3.org/TR/xhtml1/DTD/xhtml1-strict.dtd">
<html xmlns="http://www.w3.org/1999/xhtml" xml:lang="en" lang="en">
<head>
  <meta http-equiv="Content-Type" content="text/html; charset=utf-8" />
  <title>bezierwidget.cpp Example File (bezierpatch/bezierwidget.cpp)</title>
  <link rel="stylesheet" type="text/css" href="style/style.css" />
  <script src="scripts/jquery.js" type="text/javascript"></script>
  <script src="scripts/functions.js" type="text/javascript"></script>
  <script src="./scripts/superfish.js" type="text/javascript"></script>
  <link rel="stylesheet" type="text/css" href="style/superfish.css" />  <script src="./scripts/narrow.js" type="text/javascript"></script>
  <link rel="stylesheet" type="text/css" href="style/narrow.css" />
  <!--[if IE]>
<meta name="MSSmartTagsPreventParsing" content="true">
<meta http-equiv="imagetoolbar" content="no">
<![endif]-->
<!--[if lt IE 7]>
<link rel="stylesheet" type="text/css" href="style/style_ie6.css">
<![endif]-->
<!--[if IE 7]>
<link rel="stylesheet" type="text/css" href="style/style_ie7.css">
<![endif]-->
<!--[if IE 8]>
<link rel="stylesheet" type="text/css" href="style/style_ie8.css">
<![endif]-->
</head>
<body class="" onload="CheckEmptyAndLoadList();">
<table border="0" cellpadding="0" cellspacing="0" width="100%">
<tr>
<td align="left" valign="top" width="150"><img src="images/qt-logo.png" align="left" border="0" />&nbsp;&nbsp;<img src="images/qtopencl-logo.png" border="0" /></td>
<td width="1">&nbsp;&nbsp;</td><td class="postheader" valign="center"> <a href="index.html"><font color="#004faf">Home</font></a>&nbsp;&middot; <a href="qtopencl-all-classes.html"><font color="#004faf">All Classes</font></a></td>
</table><h1 class="title">bezierwidget.cpp Example File</h1>
<span class="small-subtitle">bezierpatch/bezierwidget.cpp</span>
<!-- $$$bezierpatch/bezierwidget.cpp-description -->
<div class="descr"> <a name="details"></a>
<pre class="highlightedCode brush: cpp"><span class="comment">    /****************************************************************************
    **
    ** Copyright (C) 2010 Nokia Corporation and/or its subsidiary(-ies).
    ** All rights reserved.
    ** Contact: Nokia Corporation (qt-info@nokia.com)
    **
    ** This file is part of the QtOpenCL module of the Qt Toolkit.
    **
    ** $QT_BEGIN_LICENSE:LGPL$
    ** No Commercial Usage
    ** This file contains pre-release code and may not be distributed.
    ** You may use this file in accordance with the terms and conditions
    ** contained in the Technology Preview License Agreement accompanying
    ** this package.
    **
    ** GNU Lesser General Public License Usage
    ** Alternatively, this file may be used under the terms of the GNU Lesser
    ** General Public License version 2.1 as published by the Free Software
    ** Foundation and appearing in the file LICENSE.LGPL included in the
    ** packaging of this file.  Please review the following information to
    ** ensure the GNU Lesser General Public License version 2.1 requirements
    ** will be met: http://www.gnu.org/licenses/old-licenses/lgpl-2.1.html.
    **
    ** In addition, as a special exception, Nokia gives you certain additional
    ** rights.  These rights are described in the Nokia Qt LGPL Exception
    ** version 1.1, included in the file LGPL_EXCEPTION.txt in this package.
    **
    ** If you have questions regarding the use of this file, please contact
    ** Nokia at qt-info@nokia.com.
    **
    **
    **
    **
    **
    **
    **
    **
    ** $QT_END_LICENSE$
    **
    ****************************************************************************/</span>

    #include &quot;bezierwidget.h&quot;
    #include &lt;QtCore/qtimer.h&gt;
    #include &lt;QtCore/qdatetime.h&gt;
    #include &lt;QtGui/qpainter.h&gt;
    #if QT_VERSION &gt;= 0x040700
    #define USE_VBOS 1
    #include &lt;QtOpenGL/qglbuffer.h&gt;
    #endif

<span class="comment">    /*
        The Bezier patch equation is:

        x(s, t) = S . M . Gx . transpose(M) . transpose(T)
        y(s, t) = S . M . Gy . transpose(M) . transpose(T)
        z(s, t) = S . M . Gz . transpose(M) . transpose(T)

        where:

        S  = [s^3 s^2 s 1]
        T  = [t^3 t^2 t 1]
        M  = |-1  3 -3  1|
             | 3 -6  3  0]
             |-3  3  0  0|
             | 1  0  0  0|
        Gx = | x11 x12 x13 x14 |  i.e. x components of the control points
             | x21 x22 x23 x24 |
             | x31 x32 x33 x34 |
             | x41 x42 x43 x44 |
        Gy, Gz are similar

        Note: transpose(M) = M

        From &quot;Computer Graphics: Principles and Practice&quot;, Foley, van Dam,
        et al, Second Edition, Addison Wesley, 1996.
    */</span>

    BezierWidget::BezierWidget(QWidget *parent)
        : QGLWidget(parent)
        , useOpenCL(true)
        , matrixM(-1,  3, -3,  1,
                   3, -6,  3,  0,
                  -3,  3,  0,  0,
                   1,  0,  0,  0)
        , positions(0)
        , texCoords(0)
        , indices(0)
        , numVertices(0)
        , numIndices(0)
    #ifdef QT_OPENGL_ES
        <span class="comment">// We need a value that is a multiple of 16, but less than</span>
        <span class="comment">// sqrt(65535 / 6) = 104.5 because we cannot use more than</span>
        <span class="comment">// 65535 indices under OpenGL/ES.</span>
        , subdivisionSize(96)
    #else
        , subdivisionSize(512)
    #endif
        , lastSubdivisionSize(-1)
        , textureId(0)
        , vertexBuffer(0)
        , texBuffer(0)
        , indexBuffer(0)
    {
        setAutoFillBackground(false);

        <span class="comment">// Patch is in the X-Z plane from x = 0, z = 0, to x = 3, z = 3.</span>
        <span class="comment">// The height of the patch at each control point is adjusted in Y.</span>
        cp[0]  = QVector3D(0, 0, 0);
        cp[1]  = QVector3D(1, 1, 0);
        cp[2]  = QVector3D(2, -1, 0);
        cp[3]  = QVector3D(3, 0, 0);
        cp[4]  = QVector3D(0, 0, 1);
        cp[5]  = QVector3D(1, 1, 1);
        cp[6]  = QVector3D(2, -1, 1);
        cp[7]  = QVector3D(3, 0, 1);
        cp[8]  = QVector3D(0, 0, 2);
        cp[9]  = QVector3D(1, 1, 2);
        cp[10] = QVector3D(2, -1, 2);
        cp[11] = QVector3D(3, 0, 2);
        cp[12] = QVector3D(0, 0, 3);
        cp[13] = QVector3D(1, 1, 3);
        cp[14] = QVector3D(2, -1, 3);
        cp[15] = QVector3D(3, 0, 3);

        camera.setCenter(QVector3D(1.5f, 0.0f, 1.5f));
        camera.setEye(QVector3D(-6.0f, 5.0f, 6.0f));

        QTimer *timer = new QTimer(this);
        connect(timer, SIGNAL(timeout()), this, SLOT(animate()));
        timer-&gt;start(0);

        qsrand(QDateTime::currentDateTime().toTime_t());
    }

    BezierWidget::~BezierWidget()
    {
        freeVertices();
    }

    void BezierWidget::resizeGL(int width, int height)
    {
        glViewport(0, 0, width, height);
    }

    void BezierWidget::initializeGL()
    {
        if (!context.create())
            qFatal(&quot;Could not create OpenCL context&quot;);

        program = context.buildProgramFromSourceFile(QLatin1String(&quot;:/bezierpatch.cl&quot;));
        evaluateBezier = program.createKernel(&quot;evaluateBezier&quot;);
        if (evaluateBezier.bestLocalWorkSizeImage2D().width() == 8)
            evaluateBezier.setLocalWorkSize(8, 8);

        glEnable(GL_DEPTH_TEST);

        textureImage = QImage(QLatin1String(&quot;:/qtlogo.png&quot;));
        textureId = bindTexture(textureImage);
    }

    #if !defined(QT_OPENGL_ES_2)

    static void setGLMatrix(GLenum type, const QMatrix4x4&amp; m)
    {
        glMatrixMode(type);
        if (sizeof(qreal) == sizeof(GLfloat)) {
            glLoadMatrixf(reinterpret_cast&lt;const GLfloat *&gt;(m.constData()));
        } else {
            GLfloat mat[16];
            const qreal *data = m.constData();
            for (int index = 0; index &lt; 16; ++index)
                mat[index] = data[index];
            glLoadMatrixf(mat);
        }
    }

    #endif

    void BezierWidget::paintGL()
    {
    #if !defined(QT_OPENGL_ES_2)
        glClear(GL_COLOR_BUFFER_BIT | GL_DEPTH_BUFFER_BIT);

        if (useOpenCL)
            computeVerticesCL();
        else
            computeVerticesNative();

        QMatrix4x4 proj = camera.projectionMatrix(qreal(width()) / height());
        QMatrix4x4 mv = camera.modelViewMatrix();

        setGLMatrix(GL_PROJECTION, proj);
        setGLMatrix(GL_MODELVIEW, mv);

    #ifdef USE_VBOS
        if (vertexBuffer) {
            vertexBuffer-&gt;bind();
            glVertexPointer(4, GL_FLOAT, 0, 0);
            vertexBuffer-&gt;release();
            texBuffer-&gt;bind();
            glTexCoordPointer(2, GL_FLOAT, 0, 0);
            texBuffer-&gt;release();
        } else {
            glVertexPointer(4, GL_FLOAT, 0, positions);
            glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
        }
    #else
        glVertexPointer(4, GL_FLOAT, 0, positions);
        glTexCoordPointer(2, GL_FLOAT, 0, texCoords);
    #endif

        glEnableClientState(GL_VERTEX_ARRAY);
        glEnableClientState(GL_TEXTURE_COORD_ARRAY);

        glBindTexture(GL_TEXTURE_2D, textureId);
        glEnable(GL_TEXTURE_2D);

    #ifdef USE_VBOS
        if (indexBuffer) {
            indexBuffer-&gt;bind();
            glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, 0);
            indexBuffer-&gt;release();
        } else {
            glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, indices);
        }
    #else
        glDrawElements(GL_TRIANGLES, numIndices, IndexTypeEnum, indices);
    #endif

        glDisable(GL_TEXTURE_2D);
    #endif

        qreal fps = frameRate.fps();
        if (fps &gt; 0.0f) {
            QPainter painter(this);
            QString str = QString::number(numIndices / 3) + QLatin1String(&quot; triangles, &quot;);
            str += QString::number(fps) + QLatin1String(&quot; fps&quot;);
            painter.setPen(Qt::white);
            painter.drawText(rect(), str);
        }
    }

    void BezierWidget::setUseOpenCL(bool value)
    {
        useOpenCL = value;
        freeVertices();
        frameRate.start();
    }

    void BezierWidget::setLocalWorkSize(int x, int y)
    {
        evaluateBezier.setLocalWorkSize(x, y);
        frameRate.start();
    }

    static inline qreal clamp(qreal value, qreal lower, qreal upper)
    {
        if (value &lt; lower)
            return lower;
        else if (value &gt; upper)
            return upper;
        else
            return value;
    }

    void BezierWidget::animate()
    {
        <span class="comment">// Move several of the non-corner control points up or down.</span>
        static int mapPoints[12] = {1, 2, 4, 5, 6, 7, 8, 9, 10, 11, 13, 14};
        for (int move = 0; move &lt; 4; ++move) {
            int index = mapPoints[qrand() % 12];
            qreal amt = (qrand() &amp; 1) ? 0.2f : -0.2f;
            qreal y = clamp(cp[index].y() + amt, -3.0f, 3.0f);
            cp[index].setY(y);
        }
        frameRate.newFrame();
        updateGL();
    }

    void BezierWidget::computeMatrices()
    {
        QMatrix4x4 xm(cp[0].x(), cp[1].x(), cp[2].x(), cp[3].x(),
                      cp[4].x(), cp[5].x(), cp[6].x(), cp[7].x(),
                      cp[8].x(), cp[9].x(), cp[10].x(), cp[11].x(),
                      cp[12].x(), cp[13].x(), cp[14].x(), cp[15].x());
        QMatrix4x4 ym(cp[0].y(), cp[1].y(), cp[2].y(), cp[3].y(),
                      cp[4].y(), cp[5].y(), cp[6].y(), cp[7].y(),
                      cp[8].y(), cp[9].y(), cp[10].y(), cp[11].y(),
                      cp[12].y(), cp[13].y(), cp[14].y(), cp[15].y());
        QMatrix4x4 zm(cp[0].z(), cp[1].z(), cp[2].z(), cp[3].z(),
                      cp[4].z(), cp[5].z(), cp[6].z(), cp[7].z(),
                      cp[8].z(), cp[9].z(), cp[10].z(), cp[11].z(),
                      cp[12].z(), cp[13].z(), cp[14].z(), cp[15].z());

        matrixX = matrixM * xm * matrixM;
        matrixY = matrixM * ym * matrixM;
        matrixZ = matrixM * zm * matrixM;
    }

    void BezierWidget::computeVerticesNative()
    {
        computeMatrices();
        allocVertices();

        QVector4D *posns;
        QVector2D *texcs;

    #ifdef USE_VBOS
        if (vertexBuffer) {
            vertexBuffer-&gt;bind();
            void *mapped = vertexBuffer-&gt;map(QGLBuffer::WriteOnly);
            posns = (QVector4D *)mapped;
        } else {
            posns = positions;
        }
    #else
        posns = positions;
    #endif

        <span class="comment">// Compute the positions.</span>
        for (int sint = 0; sint &lt; subdivisionSize; ++sint) {
            qreal s = qreal(sint) / (subdivisionSize - 1);
            QVector4D svec = QVector4D(s * s * s, s * s, s, 1);
            for (int tint = 0; tint &lt; subdivisionSize; ++tint) {
                qreal t = qreal(tint) / (subdivisionSize - 1);
                QVector4D tvec = QVector4D(t * t * t, t * t, t, 1);
                qreal x = QVector4D::dotProduct(svec * matrixX, tvec);
                qreal y = QVector4D::dotProduct(svec * matrixY, tvec);
                qreal z = QVector4D::dotProduct(svec * matrixZ, tvec);
                int offset = sint + tint * subdivisionSize;
                posns[offset] = QVector4D(x, y, z, 1);
            }
        }

    #ifdef USE_VBOS
        if (vertexBuffer) {
            vertexBuffer-&gt;unmap();
            vertexBuffer-&gt;release();
            texBuffer-&gt;bind();
            void *mapped = texBuffer-&gt;map(QGLBuffer::WriteOnly);
            texcs = (QVector2D *)mapped;
        } else {
            texcs = texCoords;
        }
    #else
        texcs = texCoords;
    #endif

        <span class="comment">// Compute the texture co-ordinates.</span>
        for (int sint = 0; sint &lt; subdivisionSize; ++sint) {
            qreal s = qreal(sint) / (subdivisionSize - 1);
            for (int tint = 0; tint &lt; subdivisionSize; ++tint) {
                qreal t = qreal(tint) / (subdivisionSize - 1);
                int offset = sint + tint * subdivisionSize;
                texcs[offset] = QVector2D(s, t);
            }
        }

    #ifdef USE_VBOS
        if (texBuffer) {
            texBuffer-&gt;unmap();
            texBuffer-&gt;release();
        }
    #endif
    }

    void BezierWidget::computeVerticesCL()
    {
        computeMatrices();
        allocVertices();

    #ifdef USE_VBOS
        if (vertexBuffer &amp;&amp; context.supportsObjectSharing()) {
            <span class="comment">// Acquire the vertex buffers from OpenGL.</span>
            context.acquire(positionBuffer);
            context.acquire(texCoordBuffer);
        }
    #endif

        evaluateBezier.setGlobalWorkSize(subdivisionSize, subdivisionSize);
        evaluateBezier(positionBuffer, texCoordBuffer,
                       matrixX, matrixY, matrixZ, subdivisionSize);

    #ifdef USE_VBOS
        if (vertexBuffer &amp;&amp; context.supportsObjectSharing()) {
            <span class="comment">// Release the vertex buffers from OpenCL back to OpenGL.</span>
            context.release(positionBuffer);
            context.release(texCoordBuffer).waitForFinished();
        } else if (vertexBuffer) {
            <span class="comment">// Read the results directly into the vertex buffers.</span>
            vertexBuffer-&gt;bind();
            GLfloat *mapped = (GLfloat *)vertexBuffer-&gt;map(QGLBuffer::WriteOnly);
            positionBuffer.read(mapped, numVertices * sizeof(GLfloat) * 4);
            vertexBuffer-&gt;unmap();
            vertexBuffer-&gt;release();
            texBuffer-&gt;bind();
            mapped = (GLfloat *)texBuffer-&gt;map(QGLBuffer::WriteOnly);
            texCoordBuffer.read(mapped, numVertices * sizeof(GLfloat) * 2);
            texBuffer-&gt;unmap();
            texBuffer-&gt;release();
        } else {
            positionBuffer.read(positions, numVertices * sizeof(GLfloat) * 4);
            texCoordBuffer.read(texCoords, numVertices * sizeof(GLfloat) * 2);
        }
    #else
        positionBuffer.read(positions, numVertices * sizeof(GLfloat) * 4);
        texCoordBuffer.read(texCoords, numVertices * sizeof(GLfloat) * 2);
    #endif
    }

    void BezierWidget::allocVertices()
    {
        if (subdivisionSize == lastSubdivisionSize)
            return;
        lastSubdivisionSize = subdivisionSize;

        <span class="comment">// Expand the vertex and index arrays.</span>
        int num = subdivisionSize * subdivisionSize;
        if (num &gt; numVertices) {
            positions = (QVector4D *)qRealloc(positions, num * sizeof(GLfloat) * 4);
            texCoords = (QVector2D *)qRealloc(texCoords, num * sizeof(GLfloat) * 2);

            int maxIndices = num * 6;
            indices = (IndexType *)qRealloc(indices, maxIndices * sizeof(IndexType));
        }
        numVertices = num;
    #ifdef USE_VBOS
        <span class="comment">// Create a vertex buffer in the server.</span>
        if (!vertexBuffer) {
            vertexBuffer = new QGLBuffer(QGLBuffer::VertexBuffer);
            vertexBuffer-&gt;setUsagePattern(QGLBuffer::DynamicDraw);
            texBuffer = new QGLBuffer(QGLBuffer::VertexBuffer);
            texBuffer-&gt;setUsagePattern(QGLBuffer::DynamicDraw);
            if (!vertexBuffer-&gt;create() || !texBuffer-&gt;create()) {
                delete vertexBuffer;
                vertexBuffer = 0;
                delete texBuffer;
                texBuffer = 0;
            }
        }
        if (vertexBuffer) {
            vertexBuffer-&gt;bind();
            vertexBuffer-&gt;allocate(sizeof(GLfloat) * 4 * num);
            if (!vertexBuffer-&gt;map(QGLBuffer::WriteOnly)) {
                <span class="comment">// No point using a vertex buffer if we cannot map it.</span>
                vertexBuffer-&gt;unmap();
                vertexBuffer-&gt;release();
                delete vertexBuffer;
                vertexBuffer = 0;
                delete texBuffer;
                texBuffer = 0;
            } else {
                vertexBuffer-&gt;unmap();
                vertexBuffer-&gt;release();
            }
        }
        if (texBuffer) {
            texBuffer-&gt;bind();
            texBuffer-&gt;allocate(sizeof(GLfloat) * 2 * num);
            if (!texBuffer-&gt;map(QGLBuffer::WriteOnly)) {
                <span class="comment">// No point using a vertex buffer if we cannot map it.</span>
                texBuffer-&gt;unmap();
                texBuffer-&gt;release();
                delete vertexBuffer;
                vertexBuffer = 0;
                delete texBuffer;
                texBuffer = 0;
            } else {
                texBuffer-&gt;unmap();
                texBuffer-&gt;release();
            }
        }
    #endif

        <span class="comment">// Generate a new index array for drawing the triangles.</span>
        numIndices = 0;
        for (int sint = 0; sint &lt; (subdivisionSize - 1); ++sint) {
            for (int tint = 0; tint &lt; (subdivisionSize - 1); ++tint) {
                int corner1 = sint + tint * subdivisionSize;
                int corner2 = sint + (tint + 1) * subdivisionSize;
                int corner3 = (sint + 1) + (tint + 1) * subdivisionSize;
                int corner4 = (sint + 1) + tint * subdivisionSize;
                indices[numIndices++] = corner1;
                indices[numIndices++] = corner2;
                indices[numIndices++] = corner3;
                indices[numIndices++] = corner1;
                indices[numIndices++] = corner3;
                indices[numIndices++] = corner4;
            }
        }
    #ifdef USE_VBOS
        <span class="comment">// Upload the indices into a server-side buffer.</span>
        if (!indexBuffer) {
            indexBuffer = new QGLBuffer(QGLBuffer::IndexBuffer);
            if (!indexBuffer-&gt;create()) {
                delete indexBuffer;
                indexBuffer = 0;
            }
        }
        if (indexBuffer) {
            indexBuffer-&gt;bind();
            indexBuffer-&gt;allocate(indices, sizeof(IndexType) * numIndices);
            indexBuffer-&gt;release();
        }
    #endif

        <span class="comment">// Allocate OpenCL buffers of the right size, directly on top of</span>
        <span class="comment">// the OpenGL vertex buffers if possible.</span>
    #ifdef USE_VBOS
        if (context.supportsObjectSharing()) {
            positionBuffer = context.createGLBuffer
                (vertexBuffer, QCLMemoryObject::WriteOnly);
            texCoordBuffer = context.createGLBuffer
                (texBuffer, QCLMemoryObject::WriteOnly);
        } else
    #endif
        {
            positionBuffer = context.createBufferDevice
                (num * sizeof(GLfloat) * 4, QCLMemoryObject::WriteOnly);
            texCoordBuffer = context.createBufferDevice
                (num * sizeof(GLfloat) * 2, QCLMemoryObject::WriteOnly);
        }
    }

    void BezierWidget::freeVertices()
    {
        positionBuffer = QCLBuffer();
        texCoordBuffer = QCLBuffer();
        if (positions) {
            qFree(positions);
            positions = 0;
        }
        if (texCoords) {
            qFree(texCoords);
            texCoords = 0;
        }
        if (indices) {
            qFree(indices);
            indices = 0;
        }
    #ifdef USE_VBOS
        delete vertexBuffer;
        delete texBuffer;
        delete indexBuffer;
        vertexBuffer = 0;
        texBuffer = 0;
        indexBuffer = 0;
    #endif
        lastSubdivisionSize = -1;
        numVertices = 0;
        numIndices = 0;
    }</pre>
</div>
<!-- @@@bezierpatch/bezierwidget.cpp -->
<p /><address><hr /><div align="center">
<table width="100%" cellspacing="0" border="0"><tr class="address">
<td align="left">Copyright &copy; 2010 Nokia Corporation</td>
<td align="right">QtOpenCL Documentation</td>
</tr></table></div></address>  <script src="scripts/functions.js" type="text/javascript"></script>
  <script type="text/javascript">
  var _gaq = _gaq || [];
  _gaq.push(['_setAccount', 'UA-4457116-5']);
  _gaq.push(['_trackPageview']);
  (function() {
  var ga = document.createElement('script'); ga.type = 'text/javascript'; ga.async = true;
  ga.src = ('https:' == document.location.protocol ? 'https://ssl' : 'http://www') + '.google-analytics.com/ga.js';
  var s = document.getElementsByTagName('script')[0]; s.parentNode.insertBefore(ga, s);
  })();
  </script>
</body>
</html>
